package com.gitee.wsl.mathematics.algebraic

/**
 * Represents group without neutral element (also known as inverse semigroup) i.e., algebraic structure with
 * associative, binary operation [add].
 *
 * @param T the type of element of this semispace.
 */
 interface GroupOps<T> : Algebra<T> {
    /**
     * Addition of two elements.
     *
     * @param left the augend.
     * @param right the addend.
     * @return the sum.
     */
     fun add(left: T, right: T): T

    // Operations to be performed in this context. Could be moved to extensions in case of KEEP-176.

    /**
     * The negation of this element.
     *
     * @receiver this value.
     * @return the additive inverse of this value.
     */
     operator fun T.unaryMinus(): T

    /**
     * Returns this value.
     *
     * @receiver this value.
     * @return this value.
     */
     operator fun T.unaryPlus(): T = this

    /**
     * Addition of two elements.
     *
     * @receiver the augend.
     * @param arg the addend.
     * @return the sum.
     */
     operator fun T.plus(arg: T): T = add(this, arg)

    /**
     * Subtraction of two elements.
     *
     * @receiver the minuend.
     * @param arg the subtrahend.
     * @return the difference.
     */
     operator fun T.minus(arg: T): T = add(this, -arg)

    // Dynamic dispatch of operations
    override fun unaryOperationFunction(operation: String): (arg: T) -> T = when (operation) {
        PLUS_OPERATION -> { arg -> +arg }
        MINUS_OPERATION -> { arg -> -arg }
        else -> super.unaryOperationFunction(operation)
    }

    override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = when (operation) {
        PLUS_OPERATION -> ::add
        MINUS_OPERATION -> { left, right -> left - right }
        else -> super.binaryOperationFunction(operation)
    }

     companion object {
        /**
         * The identifier of addition and unary positive operator.
         */
         const val PLUS_OPERATION: String = "+"

        /**
         * The identifier of subtraction and unary negative operator.
         */
         const val MINUS_OPERATION: String = "-"
    }
}